package com.gump.essay.redis;

import java.util.HashMap;
import java.util.Map;

/**
 * 哈希表+双向链表
 *
 * @auther zzc
 * @date 2021 04 24
 */
public class LruCache2 {

    class Node {
        int key;
        int value;
        //前节点
        Node prev;
        //后节点
        Node next;

        public Node() {
        }

        public Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private Map<Integer, Node> cache = new HashMap<Integer, Node>();
    private int size;
    private int cap;//最大容量
    private Node head, tail;//头节点  尾节点

    public LruCache2(int cap) {
        this.size = 0;
        this.cap = cap;
        //使用伪头部 尾部节点
        head = new Node();
        tail = new Node();
        head.next = tail;
        tail.prev = head;
    }

    /**
     * get
     *
     * @param key
     * @return
     */
    public int get(int key) {
        Node node = cache.get(key);
        if (node == null) {
            return -1;
        }
        //如果key存在  则通过哈希表定位，再移动到头部；
        moveToHead(node);
        return node.value;
    }

    //将节点移动到头部
    private void moveToHead(Node node) {
        removeNode(node);
        addToHead(node);
    }

    //添加到头节点
    private void addToHead(Node node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    //删除节点
    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }


    /**
     * put
     *
     * @param key
     * @param value
     */
    public void put(int key, int value) {
        Node node = cache.get(key);
        if (node == null) {
            //如果节点不存在  则创建一个新的节点
            Node newNode = new Node(key, value);
            //添加进哈希表
            cache.put(key, newNode);
            //添加至双向链表的头部
            addToHead(node);
            ++size;
            if (size > cap) {
                //超出容量  删除尾节点
                Node tail = removeTail();
                //删除哈希表中对应的项
                cache.remove(tail.key);
                --size;
            }
        }
    }

    //删除尾节点
    private Node removeTail() {
        Node res = tail.prev;
        removeNode(res);
        return res;
    }

}
